package com.hivision.streetlight.codec;

import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.Date;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;

public class ReportProcess {
    private String identifier; // 设备在应用协议里的标识

    private String msgType; // 固定值"deviceReq"，表示设备上报数据
    /**
     * 表示设备是否还有后续消息，0表示没有，1表示有，平台暂时不下发缓存命令，直到为0，下发缓存命令，不带按照0处理。
	 * 注：后续消息是指，设备上报的某条数据可能分成多次数据上报，在本次上报数据后，以hasMore字段判定后续是否还有消息。
	 * 请谨慎处理该字段，如果是必须数据上报后才有缓存命令下发的场景，只有某次数据上报时hasMore为0，缓存命令才能下发。
     */
    private int hasMore = 0;  
    private int errcode = 0;

    //serviceId=Electricity字段
    private double voltage = 0.0; // 电压
    private double current = 0;  // 电流
    private double electricityConsumption; // 用电量
//    private double frequency = 0.0; // 
//    private double powerfactor = 0.0;

    //serviceId=Temperature字段
    private double temperature = 0; // 温度
    private double humidity = 0; // 湿度
    private double illuminance=0; // 光照度
    
    //serviceId=Brightness字段
    private int brightness = 0; // 亮度
    private int signalIntensity; // 信号强度
    private int errorRate; // 误码率

    private byte noMid = 0x00;
    private byte hasMid = 0x01;
    private boolean isContainMid = false;
    private int mid = 0;
    private String uid;
    
    private int alarmType; // 报警类型
    private int cmdCode; // 指令码
    private final int CMDCODE_INDEX = 16; // 指令码字节的位置索引
    
    private int heartBeatIntervel; // 心跳间隔
    private int uploadInterval; // 数据上报间隔
    private double maxVoltagethreshold; // 过压阈值
    private double minVoltagethreshold; // 欠压阈值
    private String iotIp; // IOT平台IP地址
    private int iotPort;  // IOT平台端口

    /**
     * @param binaryData 设备发送给平台coap报文的payload部分
     *                   本例入参：AA 72 00 00 32 08 8D 03 20 62 33 99
     *                   byte[0]--byte[1]:  AA 72 命令头
     *                   byte[2]:   00 mstType 00表示设备上报数据deviceReq
     *                   byte[3]:   00 hasMore  0表示没有后续数据，1表示有后续数据，不带按照0处理
     *                   byte[4]--byte[11]:服务数据，根据需要解析//如果是deviceRsp,byte[4]表示是否携带mid, byte[5]--byte[6]表示短命令Id
     * @return
     */
    public ReportProcess(byte[] binaryData) {
    	try {
    		this.identifier = Utilty.getInstance().parseByte2AscStr(binaryData, 6, 8);
        	
        	// 指令码
        	this.cmdCode = Utilty.getInstance().bytes2Int(binaryData, CMDCODE_INDEX, 2);
            //此处需要考虑兼容性，如果没有传mId，则不对其进行解码
            this.mid = Utilty.getInstance().bytes2Int(binaryData, CMDCODE_INDEX-2, 2);
            isContainMid = true;
            //uid
            this.uid = Utilty.getInstance().parseByte2AscStr(binaryData, 6, 8);
        	
        	if(cmdCode == 0x0001 ){//心跳上传
        		msgType = "deviceReq";
        		hasMore = 0;
        		
        	}else if(cmdCode == 0x0002 ){ // 报警上传
        		msgType = "deviceReq";
        		hasMore = 0;
        		//数据部分
        		alarmType = Utilty.getInstance().bytes2Int(binaryData, 18, 2);
        	}else if(cmdCode == 0x0003){// 状态主动上传
        		msgType = "deviceReq";
        		hasMore = 0;
        		//数据部分
        		voltage= Utilty.getInstance().bytes2Int(binaryData, 18, 2)* 0.1f;
        		current = Utilty.getInstance().bytes2Int(binaryData, 20, 2)* 0.1f;
        		electricityConsumption = Utilty.getInstance().bytes2Int(binaryData, 22, 2)* 0.1f;
        		humidity = Utilty.getInstance().bytes2Int(binaryData, 24, 2)* 0.1f;
        		temperature = Utilty.getInstance().bytes2Int(binaryData, 26, 2)* 0.1f;
        		illuminance = Utilty.getInstance().bytes2Int(binaryData, 28, 2)* 0.1f;
        		brightness = Utilty.getInstance().bytes2Int(binaryData, 30, 1);
        		signalIntensity = Utilty.getInstance().bytes2Int(binaryData, 31, 1);
        		errorRate = Utilty.getInstance().bytes2Int(binaryData, 32, 1);
        	}else if(cmdCode == 0x0107){ /*平台查询参数单灯应答*/
        		msgType = "deviceRsp";
                errcode = binaryData[CMDCODE_INDEX+2];

                //数据部分
        		int index = CMDCODE_INDEX + 2;
        		heartBeatIntervel = Utilty.getInstance().bytes2Int(binaryData, index, 1);
        		uploadInterval = Utilty.getInstance().bytes2Int(binaryData, index=index+2, 1);
        		maxVoltagethreshold = Utilty.getInstance().bytes2Int(binaryData, index=index+2, 1)* 0.1f;
        		minVoltagethreshold= Utilty.getInstance().bytes2Int(binaryData, index=index+2, 1)* 0.1f;
        		iotIp = Utilty.getInstance().parseByte2IpStr(binaryData, index=index+2);
        		iotPort = Utilty.getInstance().bytes2Int(binaryData, index=index+4, 2);
        	}else if(cmdCode == 0x0108){ /*平台查询状态单灯应答*/
        		msgType = "deviceRsp";
                errcode = binaryData[CMDCODE_INDEX+2];
                //数据部分
        		voltage= Utilty.getInstance().bytes2Int(binaryData, 18, 2)* 0.1f;
        		current = Utilty.getInstance().bytes2Int(binaryData, 20, 2)* 0.1f;
        		electricityConsumption = Utilty.getInstance().bytes2Int(binaryData, 22, 2)* 0.1f;
        		humidity = Utilty.getInstance().bytes2Int(binaryData, 24, 2)* 0.1f;
        		temperature = Utilty.getInstance().bytes2Int(binaryData, 26, 2)* 0.1f;
        		illuminance = Utilty.getInstance().bytes2Int(binaryData, 28, 2)* 0.1f;
        		brightness = Utilty.getInstance().bytes2Int(binaryData, 30, 1);
        		signalIntensity = Utilty.getInstance().bytes2Int(binaryData, 31, 1);
        		errorRate = Utilty.getInstance().bytes2Int(binaryData, 32, 1);
        	}
        	else if(cmdCode == 0x0104 /* 设置单灯亮度应答*/
        			 || cmdCode == 0x0105 /*设置单灯重启应答*/
        			 || cmdCode == 0x0106 /*设置单灯参数应答*/
        			 || cmdCode == 0x0109 /*更新固件单灯应答*/
        			 || cmdCode == 0x010A /*设置IOTIP端口应答*/
        			 || cmdCode == 0x010B /*设置单灯UID应答*/
        			 || cmdCode == 0x010C /*设置单灯计量补偿值应答*/){
        		msgType = "deviceRsp";
                errcode = binaryData[CMDCODE_INDEX+2];
        	}else{
				System.out.println(String.format("error cmdCode [%s] can not found in ReportProcess", this.cmdCode));
				throw new Exception(String.format("error cmdCode [%s] can not found in ReportProcess", this.cmdCode));
        	}
        	
            // identifier参数可以根据入参的码流获得，本例指定默认值123
            // identifier = "123";

            /*
            如果是设备上报数据，返回格式为
            {
                "identifier":"123",
                "msgType":"deviceReq",
                "hasMore":0,
                "data":[{"serviceId":"Brightness",
                          "serviceData":{"brightness":50},
                          {
                          "serviceId":"Electricity",
                          "serviceData":{"voltage":218.9,"current":800,"frequency":50.1,"powerfactor":0.98},
                          {
                          "serviceId":"Temperature",
                          "serviceData":{"temperature":25},
                          ]
    	    }
    	    */
//            if (binaryData[2] == bDeviceReq) {
//                msgType = "deviceReq";
//                hasMore = binaryData[3];
    //
//                //serviceId=Brightness 数据解析
//                brightness = binaryData[4];
    //
//                //serviceId=Electricity 数据解析
//                voltage = (double) (((binaryData[5] << 8) + (binaryData[6] & 0xFF)) * 0.1f);
//                current = (binaryData[7] << 8) + binaryData[8];
//                powerfactor = (double) (binaryData[9] * 0.01);
//                frequency = (double) binaryData[10] * 0.1f + 45;
    //
//                //serviceId=Temperature 数据解析
//                temperature = (int) binaryData[11] & 0xFF - 128;
//            }
            /*
            如果是设备对平台命令的应答，返回格式为：
           {
                "identifier":"123",
                "msgType":"deviceRsp",
                "errcode":0,
                "body" :{****} 特别注意该body体为一层json结构。
            }
    	    */
//            else if (binaryData[2] == bDeviceRsp) {
//                msgType = "deviceRsp";
//                errcode = binaryData[3];
//                //此处需要考虑兼容性，如果没有传mId，则不对其进行解码
//                if (binaryData[4] == hasMid) {
//                    mid = Utilty.getInstance().bytes2Int(binaryData, 5, 2);
//                    if (Utilty.getInstance().isValidofMid(mid)) {
//                        isContainMid = true;
//                    }
//                    
//                    
    //
//                }
//            } else {
//                return;
//            }
		} catch (Exception e) {
			e.printStackTrace();
		}
    }

    public ObjectNode toJsonNode() {
        try {
            //组装body体
            ObjectMapper mapper = new ObjectMapper();
            ObjectNode root = mapper.createObjectNode();

            // root.put("identifier", this.identifier);
            root.put("identifier", this.identifier);
            root.put("msgType", this.msgType);
            root.put("hasMore", this.hasMore);
            
            //根据msgType字段组装消息体(设备主动上报数据)
            if (("deviceReq").equals(this.msgType)) {
            	
            	if(cmdCode == 0x0001 ){//心跳上传
            		ArrayNode arrynode = mapper.createArrayNode();
                    
                    ObjectNode heartBeatNode = mapper.createObjectNode();
                    heartBeatNode.put("serviceId", "StreetLightBasic");
                    ObjectNode heartBeatData = mapper.createObjectNode();
                    heartBeatData.put("cmdCode", this.cmdCode);
                    heartBeatData.put("uid", this.uid);
                    
                    heartBeatNode.put("serviceData", heartBeatData);
                    arrynode.add(heartBeatNode);
                    
                    root.put("data", arrynode);
                    
            	}else if(cmdCode == 0x0002 ){ // 报警上传
            		ArrayNode arrynode = mapper.createArrayNode();
                    
                    ObjectNode alarmNode = mapper.createObjectNode();
                    alarmNode.put("serviceId", "StreetLightBasic");
                    ObjectNode alarmData = mapper.createObjectNode();
                    alarmData.put("cmdCode", this.cmdCode);
                    alarmData.put("uid", this.uid);
                    alarmData.put("alarmType", this.alarmType);
                    
                    alarmNode.put("serviceData", alarmData);
                    arrynode.add(alarmNode);
                    
                    root.put("data", arrynode);
                    
            	}else if(cmdCode == 0x0003){// 状态主动上传
            		ArrayNode arrynode = mapper.createArrayNode();
                    
                    ObjectNode brightNode = mapper.createObjectNode();
                    brightNode.put("serviceId", "StreetLightBasic");
                    ObjectNode brightData = mapper.createObjectNode();
                    
                    brightData.put("cmdCode", this.cmdCode);
                    brightData.put("uid", this.uid);
                    
                    brightData.put("voltage", this.voltage);
                    brightData.put("current", this.current);
                    brightData.put("electricityConsumption", this.electricityConsumption);

                    brightData.put("illuminance", this.illuminance);
                    brightData.put("brightness", this.brightness);
                    brightData.put("signalIntensity", this.signalIntensity);
                    brightData.put("errorRate", this.errorRate);
                    
                    brightData.put("temperature", this.temperature);
                    brightData.put("humidity", this.humidity);
                    
                    brightNode.put("serviceData", brightData);
                    
                    arrynode.add(brightNode);

                    root.put("data", arrynode);
            	}

            } else if(("deviceRsp").equals(this.msgType)) { // 设备对平台的应答
            	
                root.put("errcode", this.errcode);
                //此处需要考虑兼容性，如果没有传mid，则不对其进行解码
                if (!isContainMid) {
                	throw new Exception(String.format("cmdCode [%s] miss mid", this.cmdCode));
                }
                //组装body体，只能为ObjectNode对象
                ObjectNode body = mapper.createObjectNode();
                ObjectNode result = mapper.createObjectNode();
                result.put("mid", this.mid);
                result.put("uid", this.uid);
                result.put("cmdCode", this.cmdCode);
                
                if(this.cmdCode == 0x0107){ /*平台查询参数单灯应答*/
                	result.put("heartBeatIntervel", this.heartBeatIntervel);
                	result.put("uploadInterval", this.uploadInterval);
                	result.put("maxVoltagethreshold", this.maxVoltagethreshold);
                	result.put("minVoltagethreshold", this.minVoltagethreshold);
                	result.put("iotIP", this.iotIp);
                	result.put("iotIP", this.iotPort);
                }else if(cmdCode == 0x0108){ /*平台查询状态单灯应答*/
                	result.put("voltage", this.voltage);
                	result.put("current", this.current);
                	result.put("electricityConsumption", this.electricityConsumption);

                	result.put("illuminance", this.illuminance);
                	result.put("brightness", this.brightness);
                	result.put("signalIntensity", this.signalIntensity);
                	result.put("errorRate", this.errorRate);
                }
                body.put("result", result);
                root.put("body", body);
            }else{
            	return null;
            }
            return root;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    
//    private String date2String(Date date){
//    	String format = "yyyyMMddTHHmmssZ";
//    	return new SimpleDateFormat(format).format(date);
//    }
    
//    private ObjectNode toLightStatusJson(){
//    	 try {
//             //组装body体
//             ObjectMapper mapper = new ObjectMapper();
//             ObjectNode root = mapper.createObjectNode();
//
//             // root.put("identifier", this.identifier);
//             root.put("msgType", this.msgType);
//             
//             root.put("hasMore", this.hasMore);
//             ArrayNode arrynode = mapper.createArrayNode();
//             
//             ObjectNode brightNode = mapper.createObjectNode();
//             brightNode.put("serviceId", "StreetLightBasic");
//             ObjectNode brightData = mapper.createObjectNode();
//             brightData.put("voltage", this.voltage);
//             brightData.put("current", this.current);
//             brightData.put("electricityConsumption", this.electricityConsumption);
//
//             brightData.put("illuminance", this.illuminance);
//             brightData.put("brightness", this.brightness);
//             brightData.put("signalIntensity", this.signalIntensity);
//             brightData.put("errorRate", this.errorRate);
//             
//             brightNode.put("serviceData", brightData);
//             
//             arrynode.add(brightNode);
//             
//             ObjectNode temperatureNode = mapper.createObjectNode();
//             temperatureNode.put("serviceId", "temperature");
//             ObjectNode temperatureData = mapper.createObjectNode();
//             temperatureData.put("temperature", this.temperature);
//             temperatureData.put("humidity", this.humidity);
//             temperatureNode.put("serviceData", temperatureData);
//             
//             arrynode.add(temperatureNode);
//             
//             return root;
//         } catch (Exception e) {
//             e.printStackTrace();
//             return null;
//         }
//    }
    
    public static void main(String[] args) {
    	
//		byte[] t = Utilty.hexString2Bytes("40231200000048562D54455354300200020000000877");
//		
//		ReportProcess reportProcess = new ReportProcess(t);
//		ObjectNode parseNode = reportProcess.toJsonNode();
//    	System.out.println(parseNode.toString());
    	
    	byte[] tt = new byte[] {(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff};
    	byte[]tt2 = {(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff};
    	
//    	System.out.println(Utilty.getInstance().parseByte2AscStr(tt, 0, 8));
    	String pp;
		try {
			pp = Utilty.getInstance().parseByte2AscStr(tt2, 0, 8);
	    	System.out.println("----->lenght:" + pp + "-------" + pp.length());
	    	byte[] tt3 = pp.getBytes("ISO8859-1");
	    	System.out.println("-----> byte lenght:" + tt3.length);
	    	System.out.println("-----> bytetosring lenght:" + Utilty.getInstance().parseByte2AscStr(tt3, 0, 8) + "-----"+Utilty.getInstance().parseByte2AscStr(tt3, 0, 8).length());
	    	String tt4 = "asdfghjk";
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch blockjj
			e.printStackTrace();
		}

    	
	}
}